#include <iostream>
#include <random>  // random_device mt19937_64 uniform_int_distribution
#include <sstream> // std::stringstream
#include <iomanip> // std::setw()
#include <atomic>

using std::cout;
using std::endl;

void test_demo()
{
    // 1.利用random_device生成机器随机数，但效率较低
    std::random_device rd;
    cout << "random_device rd = " << rd() << endl;

    // 2.利用机器随机数，通过梅森旋转算法，生成一个伪随机数
    std::mt19937_64 generator(rd());
    cout << "mt19937_64 generator(rd()) = " << generator() << endl;

    // 3.生成指定范围（0-255）之间的伪随机数
    std::uniform_int_distribution<int> distribution(0, 255);
    cout << "uniform_int_distribution<int> distribution = " << distribution(generator) << endl;

    // 4.将制定范围随机数转为16进制，存储在字符串中
    std::stringstream test_ss;
    // setw(2): 设置位宽为2     setfill(char c): 用c字符填充位宽可能的空位
    test_ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
    cout << "stringstream ss of hexadecimal = " << test_ss.str() << endl;

    // 5.由于0-255转16进制后对应位数为2，所以生成16位十六进制需要重复8次
    std::stringstream ss;
    for (int i = 0; i < 8; i++)
    {
        ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
    }
    cout << "ss = " << ss.str() << endl;
}

std::string uuid()
{
    // 1.利用random_device生成机器随机数，但效率较低
    std::random_device rd;
    // 2.利用机器随机数，通过梅森旋转算法，生成一个伪随机数
    std::mt19937_64 generator(rd());
    // 3.生成指定范围（0-255）之间的伪随机数
    std::uniform_int_distribution<int> distribution(0, 255);
    // 4.将制定范围随机数转为16进制，存储在字符串中
    // 5.由于0-255转16进制后对应位数为2，所以生成16位十六进制需要重复8次
    std::stringstream ss;
    for (int i = 0; i < 8; i++)
    {
        // setw(2): 设置位宽为2     setfill(char c): 用c字符填充位宽可能的空位
        ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
        if (i == 3 || i == 5 || i == 7)
        {
            ss << "-";
        }
    }

    // 6.追加后16位的序号
    static std::atomic<size_t> seq(1);
    size_t num = seq.fetch_add(1);
    for (int i = 7; i >= 0; i--)
    {
        ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
        if (i == 6)
        {
            ss << "-";
        }
    }

    return ss.str();
}

int main()
{
    for (int i = 0; i <= 20; i++)
    {
        cout << uuid() << endl;
    }

    return 0;
}